#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <stdlib.h>

#define LCD_PATH "/dev/fb0"

    #define __DEBUG_PRINTF__
    #include "debug.h"


typedef struct lcd_struct
{
    int fd;
	long int screensize ;
    char * fbp;
	struct fb_var_screeninfo vinfo;
	struct fb_fix_screeninfo finfo;
}lcd_t, *lcd_p_t;

void print_lcd_info(lcd_p_t lcd)
{
	/* show these information*/
	printf("vinfo.xres=%d\n",lcd->vinfo.xres);
	printf("vinfo.yres=%d\n",lcd->vinfo.yres);
	printf("vinfo.bits_per_bits=%d\n",lcd->vinfo.bits_per_pixel);
	printf("vinfo.xoffset=%d\n",lcd->vinfo.xoffset);
	printf("vinfo.yoffset=%d\n",lcd->vinfo.yoffset);
	printf("finfoline_length=%d\n",lcd->finfo.line_length);
}
int lcd_init(lcd_p_t lcd)
{
	/* open device*/
	lcd->fd = open(LCD_PATH, O_RDWR);
	if (!lcd->fd) {
		printf("Error: cannot open framebuffer device.\n");
        return -1;
	}
	DEBUG_YELLOW("The framebuffer device was opened successfully.");

	/* Get fixed screen information */
	if (ioctl(lcd->fd, FBIOGET_FSCREENINFO, &lcd->finfo)) {
		printf("Error reading fixed information.\n");
        return -1;
	}

	/* Get variable screen information */
	if (ioctl(lcd->fd, FBIOGET_VSCREENINFO, &lcd->vinfo)) {
		printf("Error reading variable information.\n");
        return -1;
	}
	/* Figure out the size of the screen in bytes */
	lcd->screensize = lcd->vinfo.xres * lcd->vinfo.yres * lcd->vinfo.bits_per_pixel / 8;
	/* Map the device to memory */
	lcd->fbp = (char *)mmap(0, lcd->screensize, PROT_READ | PROT_WRITE, MAP_SHARED, lcd->fd, 0);      
	if (lcd->fbp == NULL) 
    { 
        close(lcd->fd);
        DEBUG("Error: failed to map framebuffer device to memory."); 
        perror("");
        return -1;
    }
	DEBUG_BLUE("The framebuffer device was initialized successfully.");
    return 0;
}

void lcd_uninit(lcd_p_t lcd)
{
    DEBUG_BLUE("LCD uninit");
	munmap(lcd->fbp, lcd->screensize);  /* release the memory */
	close(lcd->fd);

}
#define SHAPE_RECTAN 0
#define SHAPE_CYCLR  1
int lcd_draw(lcd_p_t lcd, int shape_type, int x, int y, int width, int heigh ,int color)
{	
    int xx, yy;
    long int location;
    char * tmp; // equ lcd->fbp
    int lcd_width = lcd->vinfo.xres;
    tmp = lcd->fbp;
    //DEBUG_RED("x = %d, y = %d, width = %d, heigh = %d, co = 0x%x\n", x, y, width, heigh, color);
    /*
    DEBUG_GREEN("xoffset = %d, yoffset = %d, bit per pixel = %d, line_length = %d",
            lcd->vinfo.xoffset, lcd->vinfo.yoffset, lcd->vinfo.bits_per_pixel, lcd->finfo.line_length
            );
    */
    switch(shape_type)
    {
        case SHAPE_RECTAN: 
        {
    	    for(yy = 0; yy < heigh; yy++)
            {
                for(xx = 0; xx < width ; xx++)
                {
                    location =  (xx + x + lcd->vinfo.xoffset)   * (lcd->vinfo.bits_per_pixel>>3) +   
                                (yy + y + lcd->vinfo.yoffset)   * lcd->finfo.line_length;
                    *(tmp+ location) = color; 
                    *(tmp+ location + 1 ) = color;
                 }
            }
        break;
        }
        default : break;
	}
    

    return 0;
}

int lcd_get_x(lcd_p_t lcd)
{
    return lcd->vinfo.xres;
}

int lcd_get_y(lcd_p_t lcd)
{
    return lcd->vinfo.yres;
}
#if 0
// AS demo.
int main(void) 
{
    int x,y;
    int sp_x, sp_y;
    int pos_x, pos_y;
    int color;
    lcd_t lcd;
    lcd_init(&lcd);
    
    x = lcd_get_x(&lcd);
    y = lcd_get_y(&lcd);

    // Clear screen 
    memset(lcd.fbp,0,lcd.screensize);

    for(color = 0; color <= 0xff; color++)
    {
        lcd_draw(&lcd, SHAPE_RECTAN, 700, 300, 100, 50, color);
    }

    lcd_draw(&lcd, SHAPE_RECTAN, 0, 0,   800, 100, 0x0f);
    lcd_draw(&lcd, SHAPE_RECTAN, 0, 100, 800, 100, 0x12);
    lcd_draw(&lcd, SHAPE_RECTAN, 0, 300, 800, 100, 0x45);
    lcd_draw(&lcd, SHAPE_RECTAN, 0, 300, 800, 100, 0x63);
    lcd_draw(&lcd, SHAPE_RECTAN, 0, 400, 800, 100, 0x20);
    lcd_draw(&lcd, SHAPE_RECTAN, 0, 500, 800, 100, 0xff);

    print_lcd_info(&lcd);
    lcd_uninit(&lcd);
	return 0;
}
#endif
